home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / program / cgazv3n4.zip / DIF-DIR.ZIP / DIF.C < prev    next >
C/C++ Source or Header  |  1989-04-23  |  30KB  |  1,022 lines

  1. /************************** DIF.C ***************************
  2.  *
  3.  * Purpose: translate .dif files to .db3 files
  4.  * Author:  Victor Volkman
  5.  * Compilers: MSC 5.1
  6.  *            TurboC 2.0 - be sure to read TC usage note in
  7.  *                         read_dif_cell() at about line 310
  8.  *
  9.  * Usage: dif filein.dif fileout.db3 [-v]
  10.  *   translates from filein.dif to fileout.db3
  11.  *   -v flag is for verbose mode--progress messages
  12.  *       are written to stdout
  13.  *
  14.  * Source code is (c) copyright 1989 Victor Volkman
  15.  * Permission is granted to incorporate the source code into
  16.  * a larger work and to distribute compiled forms of the code.
  17.  **********************************************************/
  18.  
  19. #include <stdlib.h>    /* System #includes from your compiler */
  20. #include <io.h>
  21. #include <conio.h>
  22. #include <dos.h>
  23. #include <fcntl.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26.  
  27. #include "common.h"   /* DIF and DB3 subsystem */
  28. #include "difdata.h"
  29. #include "db3data.h"
  30. #include "difproto.h"
  31.  
  32. char *dif_hdr_strs[] = {
  33.     "TABLE", "VECTORS", "TUPLES", "DATA",
  34.     "LABEL", "COMMENT", "SIZE", "PERIDOCITY", "MAJORSTART",
  35.     "MINORSTART", "TRUELENGTH", "UNITS", "DISPLAYUNITS"
  36. };
  37.  
  38. char *dif_val_strs[] = {
  39.     "V", "NA", "ERROR", "TRUE", "FALSE", "BOT", "EOD"
  40. };
  41.  
  42. static int verbose_mode = FALSE;
  43. int error_msg();
  44. int calculate_db3_header();
  45. int dump_db3_hdr();
  46. int free_dif_hdr(), free_db3_hdr();
  47. int read_dif_cell(), check_dif_type_numeric(), check_dif_type_string();
  48.  
  49. main(argc,argv)
  50. int argc;
  51. char **argv;
  52. {
  53.     char filename1[80];
  54.     char filename2[80];
  55.  
  56.     if (argc < 2) {
  57.         printf("filename [.DIF]: ");
  58.         gets(filename1);
  59.     }
  60.     else
  61.         strcpy(filename1,argv[1]);
  62.  
  63.     if (argc < 3) {
  64.         printf("filename [.DBF]: ");
  65.         gets(filename2);
  66.     }
  67.     else
  68.         strcpy(filename2,argv[2]);
  69.  
  70.     verbose_mode = (argc==4) && strcmp(argv[3],"-v")==0;
  71.     return dif_to_db3(filename1,filename2);
  72. }
  73.  
  74.  
  75. /* The first filename is the .DIF file to read and the second filename
  76.    is the .DB3 file to write. */
  77.  
  78. int dif_to_db3(filename1, filename2)
  79. char *filename1;
  80. char *filename2;
  81. {
  82.     dif_hdr inp_hdr;
  83.     db3_hdr out_hdr;
  84.     FILE *inp_file;
  85.     int out_file;
  86.  
  87.     if ((inp_file=fopen(filename1,"r")) == NULL) {
  88.         error_msg("Unable to open <%s> for input.\n",filename1);
  89.         return FAIL;
  90.     }
  91.     if ((out_file=open(filename2,(int)(O_CREAT+O_WRONLY+O_TRUNC+O_BINARY))) < 0) {
  92.         error_msg("Unable to open <%s> for output.\n",filename2);
  93.         return FAIL;
  94.     }
  95.     if (read_reqd_dif_header(inp_file,&inp_hdr,&out_hdr) != OK)
  96.         return FAIL;
  97.     if (read_opt_dif_header(inp_file,&inp_hdr) != OK)
  98.         return FAIL;
  99.     if (read_dif_data_for_types(inp_file,&out_hdr) != OK)
  100.         return FAIL;
  101.  
  102.     calculate_db3_header(&inp_hdr,&out_hdr);
  103.     if (write_db3_header(out_file,&inp_hdr,&out_hdr) != OK)
  104.         return FAIL;
  105.  
  106.     if (verbose_mode) dump_db3_hdr(&out_hdr);
  107.  
  108.     fseek(inp_file,0L,SEEK_SET);  /* Ready for pass two */
  109.     if (read_dif_data_and_write_db3(inp_file,out_file,&out_hdr) != OK)
  110.         return FAIL;
  111.  
  112.     fclose(inp_file);
  113.     close(out_file);
  114.     free_dif_hdr(&inp_hdr);
  115.     free_db3_hdr(&out_hdr);
  116.     return OK;
  117. }
  118.  
  119.  
  120.  
  121. /*  The first header item must be the TABLE record
  122.  *
  123.  *  The second and third items must be TUPLES and VECTORS,
  124.  *  although either item may appear first.
  125.  *
  126.  *  All remaining items are optional and may include:
  127.  *  LABEL, COMMENT, SIZE, PERIDOCITY, MAJORSTART,
  128.  *  MINORSTART, TRUELENGTH, UNITS, DISPLAYUNITS
  129. */
  130.  
  131. int read_reqd_dif_header(inp_file,inp_hdr_p,out_hdr_p)
  132. FILE *inp_file;
  133. dif_hdr_p inp_hdr_p;
  134. db3_hdr_p out_hdr_p;
  135. {
  136.     dif_elt inp_hdr_elt;
  137.     enum dif_hdr_vals inp_hdr_val;
  138.     int i;
  139.  
  140.     if (verbose_mode) printf("Starting pass one...\n\n");
  141.  
  142.     if (read_dif_hdr_elt(inp_file,&inp_hdr_elt,&inp_hdr_val) != OK)
  143.         return FAIL;
  144.  
  145.     if (inp_hdr_val != DIF_TABLE) {
  146.         error_msg("Expected TABLE keyword in DIF header, found <%s>.\n",
  147.             dif_hdr_strs[ (int) inp_hdr_val]);
  148.         return FAIL;
  149.     }
  150.  
  151.     strcpy(inp_hdr_p->title, inp_hdr_elt.str_val);
  152.  
  153.     for (i=0; i<2; i++) {
  154.         if (read_dif_hdr_elt(inp_file,&inp_hdr_elt,&inp_hdr_val) != OK)
  155.             return FAIL;
  156.  
  157.         if (inp_hdr_val == DIF_VECTORS)
  158.             inp_hdr_p->num_vectors = (int)inp_hdr_elt.float_val;
  159.         else if (inp_hdr_val == DIF_TUPLES)
  160.             inp_hdr_p->num_tuples = (int)inp_hdr_elt.float_val;
  161.         else {
  162.             error_msg("Expected TUPLES or VECTORS keyword in header\n",NULL);
  163.             return FAIL;
  164.         }
  165.     }
  166.  
  167.     if (inp_hdr_p->num_vectors == 0) {  /* can't continue if VECTORS unknown */
  168.         error_msg("VECTORS keyword not found in first header items\n",NULL);
  169.         return FAIL;
  170.     }
  171.  
  172.     /* Allocate vector descriptors based on info from first three header
  173.      * records
  174.     */
  175.  
  176.     if ((inp_hdr_p->vec = (vector_desc_p) mcalloc(inp_hdr_p->num_vectors+1,
  177.         sizeof(vector_desc))) == NULL)
  178.         return FAIL;
  179.  
  180.     /* The number of DIF vectors is the same as DB3 fields */
  181.     if ((out_hdr_p->fld = (db3_hdr_elt_p) mcalloc(inp_hdr_p->num_vectors+1,
  182.         sizeof(db3_hdr_elt))) == NULL)
  183.         return FAIL;
  184.  
  185.     return OK;
  186. }
  187.  
  188.  
  189. /* Read the optional portion of the DIF input file and save all information
  190.    given about each tuple.  Not every topic parsed is relevant to the DB3
  191.    translation.  Although the DIF specification allows multiple LABEL and
  192.    COMMENT topics per tuple, the translator will only use the first one. */
  193.  
  194. int read_opt_dif_header(inp_file,inp_hdr_p)
  195. FILE *inp_file;
  196. dif_hdr_p inp_hdr_p;
  197. {
  198.     dif_elt inp_hdr_elt;
  199.     enum dif_hdr_vals inp_hdr_val;
  200.     vector_desc_p vec_p;
  201.     int numer_val;
  202.     char *str_val;
  203.  
  204.     inp_hdr_val = DIF_TABLE;
  205.     while (inp_hdr_val != DIF_DATA) {
  206.         if (read_dif_hdr_elt(inp_file,&inp_hdr_elt,&inp_hdr_val) != OK)
  207.             return FAIL;
  208.         vec_p = &inp_hdr_p->vec[inp_hdr_elt.vector];
  209.         numer_val = (int)inp_hdr_elt.float_val;
  210.         str_val = inp_hdr_elt.str_val;
  211.         switch (inp_hdr_val) {
  212.             case DIF_LABEL:
  213.                 if (vec_p->num_labels == 0)
  214.                     if ((vec_p->labels = (char **) mcalloc(NUM_STRS,
  215.                         sizeof(char **))) == NULL)
  216.                         return FAIL;
  217.                 if ((vec_p->labels[vec_p->num_labels] =
  218.                     mcalloc(DIF_STR_LEN,sizeof(char))) == NULL)
  219.                     return FAIL;
  220.                 strcpy(vec_p->labels[vec_p->num_labels++], str_val);
  221.                 break;
  222.  
  223.             case DIF_COMMENT:
  224.                 if (vec_p->num_comments == 0)
  225.                     if ((vec_p->comments = (char **) mcalloc(NUM_STRS,
  226.                         sizeof(char **))) == NULL)
  227.                         return FAIL;
  228.                 if ((vec_p->comments[vec_p->num_comments] =
  229.                     mcalloc(DIF_STR_LEN,sizeof(char))) == NULL)
  230.                     return FAIL;
  231.                 strcpy(vec_p->comments[vec_p->num_comments++], str_val);
  232.                 break;
  233.  
  234.             case DIF_SIZE:
  235.                 vec_p->size = numer_val;
  236.                 break;
  237.             case DIF_PERIODICITY:
  238.                 vec_p->period = numer_val;
  239.                 break;
  240.             case DIF_MAJORSTART:
  241.                 vec_p->majorstart = numer_val;
  242.                 break;
  243.             case DIF_MINORSTART:
  244.                 vec_p->minorstart = numer_val;
  245.                 break;
  246.             case DIF_TRUELENGTH:
  247.                 vec_p->truelength = numer_val;
  248.                 break;
  249.             case DIF_UNITS:
  250.                 strcpy(vec_p->units, str_val);
  251.                 break;
  252.             case DIF_DISPLAYUNITS:
  253.                 strcpy(vec_p->displayunits, str_val);
  254.                 break;
  255.             case DIF_DATA: /* state transition: do nothing */
  256.                 break;
  257.             default:
  258.                 printf("Internal error. %d = <%s>\n",inp_hdr_val,dif_hdr_strs[(int) inp_hdr_val]);
  259.                 return FAIL;
  260.                 /* break; */
  261.         }
  262.     }
  263.  
  264.     return OK;
  265. }
  266.  
  267.  
  268.  
  269. /* This top level of input reads a DIF header cell.  A cell in the DIF
  270.    header is preceded by a topic line.  */
  271.  
  272. int read_dif_hdr_elt(inp_file,inp_hdr_elt_p,inp_hdr_val_p)
  273. FILE *inp_file;
  274. dif_elt_p inp_hdr_elt_p;
  275. enum dif_hdr_vals *inp_hdr_val_p;
  276. {
  277.     char inp_line[80];
  278.     int found = FALSE;
  279.     int i;
  280.  
  281.     /* First, read the topic line */
  282.     if (read_dif_line(inp_file,inp_line) != OK)
  283.         return FAIL;
  284.  
  285.     for (i=0; i<=NUM_HDR_VALS; i++) {
  286.         if (stricmp(inp_line,dif_hdr_strs[i]) == 0) {
  287.             found = TRUE;
  288.             break;
  289.         }
  290.     }
  291.  
  292.     if (!found)
  293.         return FAIL;
  294.  
  295.     *inp_hdr_val_p = i;
  296.     /* Last, read the actual DIF cell */
  297.     return read_dif_cell(inp_file,inp_hdr_elt_p);
  298. }
  299.  
  300.  
  301. /* This second-to-lowest level of input reads an entire DIF cell (via
  302.    read_dif_line).  Please see the text for explanation of DIF cell
  303.    formats. */
  304.  
  305. int read_dif_cell(inp_file,cell_p)
  306. FILE *inp_file;
  307. dif_elt_p cell_p;
  308. {
  309.     char inp_line[80];
  310.     char *comma;
  311.     char *period;
  312.     int len;
  313.  
  314. /* this piece of useless code is needed to force Turbo C 2.0 to
  315.    link in the floating point scanf routines.  Otherwise TC2.0 does
  316.    not think they are needed, despite the clear usage of a double
  317.    in other scanf() calls. This code can be deleted if you have patched
  318.    your copy of TC 2.0 with the official Borland patches. These can
  319.    be obtained from:
  320.  
  321.      CompuServe: bprogb forum, lib 5: TC2PAT.ARC and PATCH.ARC
  322.  
  323. */
  324. #if defined(__TURBOC__)
  325.     float useless;
  326.     sscanf(inp_line, "%f", &useless);
  327. #endif
  328.  
  329.     if (read_dif_line(inp_file,inp_line) != OK)
  330.         return FAIL;
  331.  
  332.     if (sscanf(inp_line,"%d",&cell_p->vector) != 1) {
  333.         error_msg("Numeric value expected <%s>\n",inp_line);
  334.         return FAIL;
  335.     }
  336.  
  337.     if ((comma=strchr(inp_line,COMMA)) == NULL) {
  338.         error_msg("Comma expected <%s>\n",inp_line);
  339.         return FAIL;
  340.     }
  341.  
  342.     if ((period=strchr(inp_line,PERIOD)) == NULL)  /* Numeric Integer */
  343.         cell_p->dec_cnt = 0;
  344.     else
  345.         cell_p->dec_cnt = strlen(period+1);
  346.  
  347.     if (sscanf(comma+1,"%lf",&cell_p->float_val) != 1) {
  348.         error_msg("Float value expected <%s>\n",inp_line);
  349.         return FAIL;
  350.     }
  351.  
  352.     cell_p->numer_len = strlen(comma+1);
  353.     if (read_dif_line(inp_file,inp_line) != OK)
  354.         return FAIL;
  355.  
  356.     len = strlen(inp_line);
  357.     if (inp_line[0]!=QUOTE || inp_line[len-1]!=QUOTE) {
  358.         strcpy(cell_p->str_val,inp_line);  /* No quotes, copy as is */
  359.         return OK;
  360.     }
  361.  
  362.     inp_line[len-1] = '\0';    /* copy inp_line minus quotes */
  363.     strcpy(cell_p->str_val,inp_line+1);
  364.     return OK;
  365. }
  366.  
  367.  
  368.  
  369. int read_dif_line(inp_file,inp_line)  /* Lowest level of DIF input */
  370. FILE *inp_file;
  371. char *inp_line;
  372. {
  373.     static int cur_line=0;
  374.  
  375.     if (fgets(inp_line, DIF_STR_LEN, inp_file) == NULL) {
  376.         error_msg("Premature end-of-file on input.\n",NULL);
  377.         return FAIL;
  378.     }
  379.     inp_line[strlen(inp_line)-1] = '\0';
  380.  
  381.     if (verbose_mode) printf("%05d: %s\n",cur_line++,inp_line);
  382.     return OK;
  383. }
  384.  
  385.  
  386. /* The primary task of pass one is to determine the DB3 field types
  387.    which correspond to the DIF vectors.  The DB3 field types are
  388.    determined gradually by check_dif_type_numic() and
  389.    check_dif_type_string() */
  390.  
  391. int read_dif_data_for_types(inp_file,out_hdr_p)
  392. FILE *inp_file;
  393. db3_hdr_p out_hdr_p;
  394. {
  395.     db3_hdr_elt_p fld_p;
  396.     enum dif_val_vals inp_val;
  397.     dif_elt inp_cell;
  398.     int vector = 0;
  399.     int done = FALSE;
  400.  
  401.     while (!done) {
  402.         read_dif_cell(inp_file,&inp_cell);
  403.         fld_p = &out_hdr_p->fld[vector];
  404.         switch (inp_cell.vector) {
  405.             case DIF_TYPE_SPECIAL:
  406.                 if (lookup_val_strs(inp_cell.str_val,&inp_val)!=OK)
  407.                     return FAIL;
  408.                 switch (inp_val) {
  409.                     case DIF_VAL_BOT:  /* Beginning of Tuple */
  410.                         vector = 0;
  411.                         continue;
  412.                     case DIF_VAL_EOD:  /* End of Data        */
  413.                         done = TRUE;
  414.                         break;
  415.                     default:
  416.                         error_msg("Expected BOT or EOD val\n",NULL);
  417.                 }
  418.                 break;
  419.  
  420.             case DIF_TYPE_NUMERIC:
  421.                 check_dif_type_numeric(&inp_cell,fld_p);
  422.                 break;
  423.  
  424.             case DIF_TYPE_STRING:
  425.                 check_dif_type_string(&inp_cell,fld_p);
  426.                 break;
  427.         }
  428.  
  429.         vector++;
  430.     }
  431.  
  432.     return OK;
  433. }
  434.  
  435.  
  436. /* Calculate the remaining fields in the DB3 header so we can write it.
  437.    Note that a DIF tuple is indeed the sames as a DB3 record.  Also,
  438.    DIF LABELS are converted to their DB3 equivalents as field names. */
  439.  
  440. int calculate_db3_header(inp_hdr_p,out_hdr_p)
  441. dif_hdr_p inp_hdr_p;
  442. db3_hdr_p out_hdr_p;
  443. {
  444.     int i;
  445.     db3_hdr_elt_p fld_p;
  446.     vector_desc_p vec_p;
  447.  
  448. #if defined(__TURBOC__)
  449.     struct date cur_date;
  450.     getdate(&cur_date);
  451.     out_hdr_p->last_upd[UPD_YY] = (char)(cur_date.da_year - 1900);
  452.     out_hdr_p->last_upd[UPD_MM] = (char)cur_date.da_mon;
  453.     out_hdr_p->last_upd[UPD_DD] = (char)cur_date.da_day;
  454.  
  455. #else /* MSC */
  456.     struct dosdate_t cur_date;    /* from INT 21h */
  457.     _dos_getdate(&cur_date);  /* Use DOS date as internal file date */
  458.     out_hdr_p->last_upd[UPD_YY] = (char)(cur_date.year - 1900);
  459.     out_hdr_p->last_upd[UPD_MM] = (char)cur_date.month;
  460.     out_hdr_p->last_upd[UPD_DD] = (char)cur_date.day;
  461.  
  462. #endif
  463.  
  464.     out_hdr_p->ver_no = DB3_FILE_TYPE;
  465.     out_hdr_p->num_recs = inp_hdr_p->num_tuples;
  466.     out_hdr_p->size_hd = DB3_HDR_SIZE * (inp_hdr_p->num_vectors + 1) + 2;
  467.  
  468.     out_hdr_p->size_rec = 1;     /* 1 byte for active record flag */
  469.     for (i=0; i < inp_hdr_p->num_vectors; i++) {
  470.         fld_p = &out_hdr_p->fld[i];
  471.         vec_p = &inp_hdr_p->vec[i];
  472.  
  473.         /* Attach DIF LABEL as field name, if any */
  474.         if (vec_p->num_labels)
  475.             build_db3_name_from_label(fld_p->fld_name, *vec_p->labels);
  476.         else
  477.             sprintf(fld_p->fld_name,"Field_%03d",i);
  478.  
  479.         /* Setup field sizes for DATE and LOGICAL fields */
  480.         if (fld_p->fld_type == DB3_DATE)
  481.             fld_p->fld_size = DB3_DATE_SIZE;
  482.         else if (fld_p->fld_type == DB3_LOGICAL)
  483.             fld_p->fld_size = DB3_LOGICAL_SIZE;
  484.         else if (fld_p->fld_type == DB3_NONE) {  /* empty vector, set defs. */
  485.             fld_p->fld_type = DB3_CHAR;
  486.             fld_p->fld_size = DB3_DEFAULT_SIZE;
  487.         }
  488.  
  489.         /* Compute record size, data address is offset into the record */
  490.         fld_p->fld_data_addr = out_hdr_p->size_rec;
  491.         out_hdr_p->size_rec += fld_p->fld_size;
  492.     }
  493.  
  494.     /* This buffer will store one record during I/O */
  495.     if ((out_hdr_p->data=mcalloc(out_hdr_p->size_rec,sizeof(char))) == NULL)
  496.         return FAIL;
  497.     *out_hdr_p->data = BLANK;  /* mark as non-deleted */
  498.  
  499.     return OK;
  500. }
  501.  
  502. /* Create a valid DB3 field name based on the DIF label. Note that DB3
  503.    names may contain a maximum of 10 characters with no embedded blanks. */
  504.  
  505. int build_db3_name_from_label(db3_name, dif_name)
  506. char *db3_name;      /* DB3 name we're going to build   */
  507. char *dif_name;      /* DIF LABEL that name is based on */
  508. {
  509.     int i=0;
  510.  
  511.     while (*dif_name != '\0') {
  512.         if (*dif_name != BLANK)
  513.             *db3_name++ = *dif_name++;
  514.         else {
  515.             *db3_name = UNDERSCORE;  /* replace BLANK */
  516.             dif_name++;
  517.         }
  518.         if (i++ == DB3_NAME_LEN-2)
  519.             break;
  520.     }
  521.  
  522.     *db3_name = '\0';
  523.     return OK;
  524. }
  525.  
  526.  
  527.  
  528. /* Write out the DB3 from the information collected in pass one.
  529.    Note the trailing zeroes following the actual header data. */
  530.  
  531. int write_db3_header(out_file,inp_hdr_p,out_hdr_p)
  532. int out_file;           /* DB3 file that we're writing */
  533. dif_hdr_p inp_hdr_p;    /* DIF header from input file  */
  534. db3_hdr_p out_hdr_p;    /* DB3 header for output file  */
  535. {
  536.     int i;
  537.     int end_of_headers = 0x000D;
  538.     char zeroes[DB3_HDR_SIZE-DB3_HDR_ACTUAL_SIZE];
  539.  
  540.     memset(zeroes, 0, sizeof(zeroes));
  541.     write(out_file, (char *)out_hdr_p, DB3_HDR_SIZE);
  542.     for (i=0; i < inp_hdr_p->num_vectors; i++) {
  543.         write(out_file, (char *)&out_hdr_p->fld[i], DB3_HDR_ACTUAL_SIZE);
  544.         write(out_file, zeroes, DB3_HDR_SIZE-DB3_HDR_ACTUAL_SIZE);
  545.     }
  546.  
  547.     write(out_file, (char *)&end_of_headers, sizeof(int));
  548.     return OK;
  549. }
  550.  
  551. /* During pass two over the input file, we will skip over the header
  552.    and convert each cell into the native DB3 format */
  553.  
  554. int read_dif_data_and_write_db3(inp_file,out_file,out_hdr_p)
  555. FILE *inp_file;
  556. int out_file;
  557. db3_hdr_p out_hdr_p;
  558. {
  559.     enum dif_hdr_vals inp_hdr_val;
  560.     enum dif_val_vals inp_val;
  561.     dif_elt inp_cell;
  562.     int vector = 0;
  563.     int tuple = 0;
  564.     int done = FALSE;
  565.  
  566.     if (verbose_mode) printf("Starting pass two...\n\n");
  567.  
  568.     /* First, skip past header records */
  569.     inp_hdr_val = DIF_TABLE;
  570.     while (inp_hdr_val != DIF_DATA)   /* Flag for start of data */
  571.         if (read_dif_hdr_elt(inp_file,&inp_cell,&inp_hdr_val) != OK)
  572.             return FAIL;
  573.  
  574.     while (!done) {
  575.         read_dif_cell(inp_file,&inp_cell);
  576.         switch (inp_cell.vector) {
  577.             case DIF_TYPE_SPECIAL:
  578.                 lookup_val_strs(inp_cell.str_val,&inp_val);
  579.                 switch (inp_val) {
  580.                     case DIF_VAL_BOT:  /* Beginning of Tuple */
  581.                         if (tuple)
  582.                             write(out_file, out_hdr_p->data, out_hdr_p->size_rec);
  583.                         vector = 0;
  584.                         tuple++;
  585.                         continue;
  586.                     case DIF_VAL_EOD:  /* End of Data        */
  587.                         write(out_file, out_hdr_p->data, out_hdr_p->size_rec);
  588.                         done = TRUE;
  589.                         break;
  590.                     default:
  591.                         error_msg("Expected BOT or EOD val, found <%s>\n",
  592.                             dif_val_strs[inp_val]);
  593.                 }
  594.                 break;
  595.  
  596.             case DIF_TYPE_NUMERIC:  /* Insert cell into output buffer */
  597.                 add_dif_numeric_to_db3_record(vector,&inp_cell,out_hdr_p);
  598.                 break;
  599.  
  600.             case DIF_TYPE_STRING:   /* Insert cell into output buffer */
  601.                 add_dif_string_to_db3_record(vector,&inp_cell,out_hdr_p);
  602.                 break;
  603.         }
  604.  
  605.         vector++;
  606.     }
  607.     return OK;
  608. }
  609.  
  610.  
  611. /* Format a DIF string cell into the record I/O buffer */
  612.  
  613. int add_dif_numeric_to_db3_record(vector,inp_cell_p,out_hdr_p)
  614. int vector;                /* current DIF vector            */
  615. dif_elt_p inp_cell_p;      /* DIF cell we're going to add   */
  616. db3_hdr_p out_hdr_p;       /* DB3 header where data will go */
  617. {
  618.     db3_hdr_elt_p fld_p;
  619.     char *data_p;
  620.     char temp[8];
  621.     char format[10];
  622.     char local[20];
  623.     int size;
  624.  
  625.     fld_p = &out_hdr_p->fld[vector];
  626.     data_p = out_hdr_p->data + fld_p->fld_data_addr;
  627.     size = fld_p->fld_size;
  628.     memset(data_p, BLANK, size);
  629.  
  630.     switch(fld_p->fld_type) {
  631.         case DB3_NUMERIC:
  632.         case DB3_CHAR:
  633.             strcpy(format,"%16.");
  634.             itoa((int)fld_p->fld_dec_cnt,temp,4);
  635.             strcat(format,temp);
  636.             strcat(format,"f");
  637.             sprintf(local,format,inp_cell_p->float_val);
  638.             strncpy(data_p,local+strlen(local)-size,size);
  639.             break;
  640.         case DB3_LOGICAL:
  641.             *data_p = inp_cell_p->float_val ? (char)'T' : (char)'F';
  642.             break;
  643.         default:
  644.             error_msg("Type determination failure, non-numeric data\n",NULL);
  645.     }
  646.     return OK;
  647. }
  648.  
  649.  
  650. /* Format a DIF string cell into the record I/O buffer */
  651.  
  652. int add_dif_string_to_db3_record(vector,inp_cell_p,out_hdr_p)
  653. int vector;               /* current DIF vector            */
  654. dif_elt_p inp_cell_p;     /* DIF cell we're going to add   */
  655. db3_hdr_p out_hdr_p;      /* DB3 header where data will go */
  656. {
  657.     db3_hdr_elt_p fld_p;
  658.     char *data_p;
  659.     int size;
  660.     int len;
  661.  
  662.     fld_p = &out_hdr_p->fld[vector];
  663.     data_p = out_hdr_p->data + fld_p->fld_data_addr;
  664.     size = fld_p->fld_size;
  665.     len = strlen(inp_cell_p->str_val);
  666.     memset(data_p, BLANK, size);
  667.  
  668.     switch(fld_p->fld_type) {
  669.         case DB3_CHAR:
  670.             strncpy(data_p,inp_cell_p->str_val,len);
  671.             break;
  672.         case DB3_DATE:
  673.             format_db3_date_from_string(data_p,inp_cell_p->str_val);
  674.             break;
  675.         case DB3_NUMERIC:
  676.             error_msg("a db3 numeric field cannot receive a string value\n",NULL);
  677.             break;
  678.         case DB3_LOGICAL:
  679.             format_db3_logical_from_string(data_p,inp_cell_p->str_val);
  680.             break;
  681.         default:
  682.             error_msg("Type determination failure, non-numeric data\n",NULL);
  683.     }
  684.     return OK;
  685. }
  686.  
  687.  
  688. /* Examine the DIF number in the cell and try to find which type of
  689.    DB3 field would best accommodate it.  */
  690.  
  691. int check_dif_type_numeric(inp_cell_p,fld_p)
  692. dif_elt_p inp_cell_p;
  693. db3_hdr_elt_p fld_p;
  694. {
  695.     enum dif_val_vals inp_val;
  696.  
  697.     if (lookup_val_strs(inp_cell_p->str_val,&inp_val)!=OK)
  698.         return FAIL;
  699.     /* Actions based on previous notion of field type */
  700.     switch (fld_p->fld_type) {
  701.         case DB3_NONE:
  702.             switch (inp_val) {
  703.                 case DIF_VAL_V:
  704.                 case DIF_VAL_NA:
  705.                 case DIF_VAL_ERROR:
  706.                     fld_p->fld_type = DB3_NUMERIC;
  707.                     break;
  708.                 case DIF_VAL_TRUE:
  709.                 case DIF_VAL_FALSE:
  710.                     fld_p->fld_type = DB3_LOGICAL;
  711.                     break;
  712.             }
  713.             break;
  714.  
  715.         case DB3_CHAR:
  716.             if (inp_cell_p->numer_len > fld_p->fld_size)
  717.                 fld_p->fld_size = (char)inp_cell_p->numer_len;
  718.             break;
  719.  
  720.         case DB3_DATE:
  721.             fld_p->fld_type = DB3_CHAR;    /* DATE not conformable to NUMERIC */
  722.             break;
  723.  
  724.         case DB3_LOGICAL:
  725.             switch (inp_val) {
  726.                 case DIF_VAL_V:
  727.                 case DIF_VAL_NA:
  728.                 case DIF_VAL_ERROR:
  729.                     fld_p->fld_type = DB3_NUMERIC;
  730.                     break;
  731.             }
  732.             break;
  733.     }
  734.  
  735.     if (fld_p->fld_type == DB3_NUMERIC) {
  736.         if (inp_cell_p->dec_cnt > fld_p->fld_dec_cnt)
  737.             fld_p->fld_dec_cnt = (char)inp_cell_p->dec_cnt;
  738.         if (inp_cell_p->numer_len > fld_p->fld_size)
  739.             fld_p->fld_size = (char)inp_cell_p->numer_len;
  740.     }
  741.  
  742.     return OK;
  743. }
  744.  
  745.  
  746. /* Examine the DIF string in the cell and try to find which type of
  747.    DB3 field would best accommodate it.  */
  748.  
  749. int check_dif_type_string(inp_cell_p,fld_p)
  750. dif_elt_p inp_cell_p;   /* DIF cell to check   */
  751. db3_hdr_elt_p fld_p;    /* DB3 field to modify */
  752. {
  753.     char *str;
  754.     int len;
  755.     str = inp_cell_p->str_val;
  756.  
  757.     /* Actions based on previous notion of field type */
  758.     switch (fld_p->fld_type) {
  759.         case DB3_NONE:
  760.             if (strlen(str)==0)   /* Can't make a decision on empty strings */
  761.                 break;
  762.             if (is_logical(str))
  763.                 fld_p->fld_type = DB3_LOGICAL;
  764.             else if (is_date(str))
  765.                 fld_p->fld_type = DB3_DATE;
  766.             else
  767.                 fld_p->fld_type = DB3_CHAR;
  768.             break;
  769.  
  770.         case DB3_DATE:
  771.             if (!is_date(str))            /* Not a DATE string    */
  772.                 fld_p->fld_type = DB3_CHAR;
  773.             break;
  774.  
  775.         case DB3_LOGICAL:
  776.             if (!is_logical(str))         /* Not a LOGICAL string */
  777.                 fld_p->fld_type = DB3_CHAR;
  778.             break;
  779.  
  780.         case DB3_NUMERIC:
  781.             fld_p->fld_type = DB3_CHAR;
  782.             break;
  783.     }
  784.  
  785.     if (fld_p->fld_type == DB3_CHAR) {
  786.         len = strlen(inp_cell_p->str_val);
  787.         if (len > fld_p->fld_size)
  788.             fld_p->fld_size = (char)len;
  789.     }
  790.  
  791.     return OK;
  792. }
  793.  
  794.  
  795. /* Translate the string into its corresponding enumerated value */
  796.  
  797. int lookup_val_strs(str,val_p)
  798. char *str;
  799. enum dif_val_vals *val_p;
  800. {
  801.     int found = FALSE;
  802.     int i;
  803.  
  804.     for (i=0; i<=NUM_VAL_VALS; i++)
  805.         if (stricmp(str,dif_val_strs[i]) == 0) {
  806.             found = TRUE;
  807.             *val_p = i;
  808.             break;
  809.         }
  810.  
  811.     if (!found) {
  812.         error_msg("Unknown value indicator <%s>\n",str);
  813.         return FAIL;
  814.     }
  815.  
  816.     return OK;
  817. }
  818.  
  819.  
  820.  
  821. /* Free all vectors and vector data (labels and comments) in the
  822.    DIF header */
  823.  
  824. int free_dif_hdr(inp_hdr_p)
  825. dif_hdr_p inp_hdr_p;
  826. {
  827.     vector_desc_p vec_p;
  828.     int i;
  829.     int cur_item;
  830.  
  831.     for (i=0; i < inp_hdr_p->num_vectors; i++) {
  832.         vec_p = &inp_hdr_p->vec[i];
  833.         for (cur_item=0; cur_item < vec_p->num_labels; cur_item++)
  834.             mfree(vec_p->labels[cur_item]);
  835.         for (cur_item=0; cur_item < vec_p->num_comments; cur_item++)
  836.             mfree(vec_p->comments[cur_item]);
  837.         if (vec_p->labels != NULL)
  838.             mfree((char *)vec_p->labels);
  839.         if (vec_p->comments != NULL)
  840.             mfree((char *)vec_p->comments);
  841.     }
  842.  
  843.     mfree((char *)inp_hdr_p->vec);  /* Lastly, free all the fields */
  844.     inp_hdr_p->vec = NULL;
  845.     return OK;
  846. }
  847.  
  848.  
  849. int free_db3_hdr(out_hdr_p)   /* Free the DB3 header and all fields */
  850. db3_hdr_p out_hdr_p;
  851. {
  852.     mfree(out_hdr_p->data);
  853.     mfree((char *)out_hdr_p->fld);
  854.     out_hdr_p->data = NULL;
  855.     out_hdr_p->fld = NULL;
  856.     return OK;
  857. }
  858.  
  859.  
  860. char *mcalloc(num,size)  /* Just one level above ordinary calloc() */
  861. int num;
  862. int size;
  863. {
  864.     char *retval;
  865.  
  866.     retval = calloc(num,size);
  867.     if (retval == NULL)
  868.         error_msg( "Insufficient memory\n",NULL);
  869.     return retval;
  870. }
  871.  
  872.  
  873. int mfree(ptr)    /* Just one level above ordinary free() */
  874. char *ptr;
  875. {
  876.     if (ptr==NULL)
  877.         error_msg( "Attempt to free NULL ptr\n",NULL);
  878.     else
  879.         free(ptr);
  880.     return OK;
  881. }
  882.  
  883.  
  884. int error_msg(format_str,data_str)  /* customize for your application */
  885. char *format_str;
  886. char *data_str;
  887. {
  888.     fprintf(stdout,format_str,data_str);
  889.     return OK;
  890. }
  891.  
  892.  
  893. int is_date(test_str)  /* See if this string contains date data */
  894. char *test_str;
  895. {
  896.     char dest_str[20];
  897.  
  898.     return format_db3_date_from_string(dest_str, test_str);
  899. }
  900.  
  901.  
  902.  
  903. /* convert from any valid date format in the source string ("MM/DD/YY",
  904.    "MM/DD/YYYY", "MM-DD-YY", "MM-DD-YYYY", "MM.DD.YY", or "MM.DD.YYY")
  905.    to the DB3 destination date format "YYMMDD". */
  906.  
  907. int format_db3_date_from_string(dest_str, source_str)
  908. char *dest_str;
  909. char *source_str;
  910. {
  911.     char local[80];
  912.     char *ptr;
  913.     int month, day, year;
  914.     int dashes=0;
  915.     int slashes=0;
  916.     int periods=0;
  917.  
  918.     /* Convert the source string to a parsable format, while checking
  919.        validity along the way */
  920.     strcpy(local,source_str);
  921.     for (ptr=local; *ptr!='\0'; ptr++) {
  922.         if (*ptr == PERIOD) {
  923.             *ptr = SLASH;
  924.             periods++;
  925.         }
  926.         else if (*ptr == SLASH)
  927.             slashes++;
  928.         else if (*ptr == DASH) {
  929.             *ptr = SLASH;
  930.             dashes++;
  931.         }
  932.         else if (*ptr < '0' || *ptr > '9')
  933.             return FAIL;
  934.     }
  935.  
  936.     /* Valid date formats:  mm/dd/yy, mm-dd-yy, mm.dd.yy  */
  937.     if ((periods==2 && slashes==0 && dashes==0) ||
  938.         (periods==0 && slashes==2 && dashes==0) ||
  939.         (periods==0 && slashes==0 && dashes==2))  {
  940.  
  941.         if (sscanf(local,"%d/%d/%d",&month,&day,&year) < 3)
  942.             return FAIL;
  943.         if (year < 100)     /* convert two digit to four digit years */
  944.             year += 1900;
  945.         if (!month || !day)
  946.             return FAIL;
  947.         sprintf(local,"%04d%02d%02d",year,month,day);
  948.         strncpy(dest_str, local, strlen(local));
  949.     }
  950.     else
  951.         return FAIL;
  952.  
  953.     return OK;
  954. }
  955.  
  956.  
  957. int is_logical(str)  /* See if this string contains logical data */
  958. char *str;
  959. {
  960.     char dest_str[2];
  961.  
  962.     return format_db3_logical_from_string(dest_str,str);
  963. }
  964.  
  965. /* If the source string is a DB3 logical (Y, T, N, or F) then
  966.    copy it to the destination string, else the result is blank */
  967.  
  968. int format_db3_logical_from_string(dest_str, source_str)
  969. char *dest_str;
  970. char *source_str;
  971. {
  972.     *dest_str = BLANK;
  973.     if (strlen(source_str) != 1)
  974.         return FAIL;
  975.  
  976.     if (strpbrk(source_str,"yYtTnNfF") != NULL) {
  977.         *dest_str = *source_str;
  978.         return OK;
  979.     }
  980.     return FAIL;
  981. }
  982.  
  983.  
  984. #define calc_num_flds(size_hd)  ((size_hd - 2) / DB3_HDR_SIZE - 1)
  985.  
  986. int dump_db3_hdr(inp_hdr_p)
  987. db3_hdr_p inp_hdr_p;
  988. {
  989.     int num_flds;
  990.     int i;
  991.  
  992.     num_flds = calc_num_flds(inp_hdr_p->size_hd);
  993.     printf("DBase III  -  .DBF Header Report\n\n\n");
  994.     printf("DBase version:  %d\n",inp_hdr_p->ver_no & 0x7F);
  995.     if (inp_hdr_p->ver_no & 0x80)
  996.         printf("This file contains memo fields and requires ancilliary .DBT file\n");
  997.     printf("Last update: %02d/%02d/%02d\n",inp_hdr_p->last_upd[UPD_MM],
  998.         inp_hdr_p->last_upd[UPD_DD], inp_hdr_p->last_upd[UPD_YY]);
  999.     printf("Number of records:    %ld\n",inp_hdr_p->num_recs);
  1000.     printf("Size of header area:  %d bytes\n",inp_hdr_p->size_hd);
  1001.     printf("Size of a record:     %d bytes\n",inp_hdr_p->size_rec);
  1002.  
  1003.     printf("\n\n\nDBase III  -  .DBF Field Header Report\n\n\n");
  1004.     printf("Name       | Type | Data Addr | Size | Dec Cnt \n");
  1005.     printf("-----------+------+-----------+------+---------\n");
  1006.  
  1007.     for (i=0; i<num_flds; i++)
  1008.         dump_db3_hdr_elt(&inp_hdr_p->fld[i]);
  1009.  
  1010.     return OK;
  1011. }
  1012.  
  1013.  
  1014. dump_db3_hdr_elt(fld_p)  /* Dump a report of a single DB3 field */
  1015. db3_hdr_elt_p fld_p;
  1016. {
  1017.     printf("%-11s|  %c   | %8lX  | %3d  |%2d\n",fld_p->fld_name,
  1018.         fld_p->fld_type, fld_p->fld_data_addr, fld_p->fld_size,
  1019.         fld_p->fld_dec_cnt);
  1020.     return OK;
  1021. }
  1022.